package org.jugile.util;

import java.util.ArrayList;
import java.util.List;

/**
 * God says to Israel, to sons of Jacob:
 * "For thou art an holy people unto the LORD thy God: 
 *  the LORD thy God hath chosen thee to be a special people unto himself, 
 *  above all people that are upon the face of the earth." (5.Moos 7:6)  
 * ==========
 *  
 * SrcLine is simple utility to parse and handle indention formatted source files.
 *  
 * @author jukka.rahkonen@iki.fi
 */
public class SrcLine extends Jugile {

	private int num;
	private String line;
	private SrcLine parent = null;
	private List<SrcLine> sublines = new ArrayList<SrcLine>();
	public List<SrcLine> getLines() { return sublines; }
	public boolean hasSublines() { return sublines.size() > 0; }
	
	public int getLineNum() { return num; }
	public String getLine() { return line; }
	
	private SrcLine(int num, String line) {
		// use only for root node
		this.num = num;
		this.line = line;
	}

	private SrcLine add(int num, String line) {
		SrcLine sub = new SrcLine(num,line);
		sub.parent = this;
		sublines.add(sub);
		return sub;
	}

	private int getLevel() { 
		if (parent == null) return 0;
		return parent.getLevel()+1;
	}
	
	private SrcLine getRoot() { return getLevel(0); }
	private SrcLine getLevel(int level) {
		if (level < 0) fail("level < 0");
		if (level == getLevel()) return this;
		return parent.getLevel(level);
	}

	public String toString() {
		StringBuffer buf = new StringBuffer();
		dump(buf);
		return buf.toString();
	}
	private void dump(StringBuffer buf) {
		if (parent != null) {
			String ind = mult(" ",(getLevel()-1)*indentCount);
			buf.append(String.format("%4d: (%2d) %s%s\n", num, getLevel(), ind, line));
		}
		for (SrcLine l : sublines) l.dump(buf);
	}
	
	private static int indentCount = 2;
	public static SrcLine parse(String filename) {
		SrcLine parent = new SrcLine(0,null);
		SrcLine prev = null;
		Blob b = new Blob(filename);
		int linenum = 0;
		for (String line : b.getLines()) {
			linenum++;
			int ind = countIndent(line);
			line = line.trim();
			if (line.startsWith("#")) continue;
			if (ind % indentCount != 0) error("indent="+ind,linenum,line);
			int level = ind/indentCount;
			//print("level: " + level+ " line: " +line);
			if (empty(line)) {
				if (level == 0 || prev == null) continue;
				if (level != prev.getLevel()-1) continue;
			}
			if (level > parent.getLevel()) {
				if (level > parent.getLevel()+1) error("invalid indent increase",linenum,line);
				parent = prev;
			} else if (level < parent.getLevel()) {
				parent = parent.getLevel(level);
			}
			prev = parent.add(linenum, line);
		}
		return parent.getRoot();
	}

	
	private static void error(String msg, int num, String line) {
		fail("parse error: " + msg + " in line " +num+ ": " + line);
	}

}
